package raycast;


import java.awt.image.BufferedImage;

import model.Scene;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import scparser.Parser;
import scparser.ParserHelper;
import scparser.factory.primitiveFactory.FactoryException;

public class RayCastMain {
	private static Options options;
	private static Option i;
	private static Option o;
	private static Option size;
	private static Option fov;
	private static Option time;
	private static final String EXTENSION = ".sc";
	
	public static void main(String[] args) {
		CommandLineParser parser = new GnuParser();
		init();
		HelpFormatter formatter = new HelpFormatter();
		
		try {
	        // parse the command line arguments
	        CommandLine line = parser.parse( options, args );
	        
	        String inputFileName = line.getOptionValue("i");
	        String outputFileName;
	        String imageExtension = null;
	        int fov = 60;
	        String[] size = line.getOptionValue("size").split("x");
	        int width = Integer.parseInt(size[0]);
	        int height = Integer.parseInt(size[1]);
	        long time = System.currentTimeMillis();
	        
	        if (!EXTENSION.equals(inputFileName.substring(inputFileName.length()-3))) {
	        	System.out.println("error input file type, it is must be .sc file");
	        	System.exit(-1);
	        }
	        
	        if (line.hasOption("fov")) {
	        	fov = Integer.parseInt(line.getOptionValue("fov"));
	        }
	        
	        if (line.hasOption("o")) {
	        	outputFileName = line.getOptionValue("o");
	        	imageExtension = outputFileName.substring(outputFileName.length()-3);
	        } else {
	        	imageExtension = "png";
	        	outputFileName = inputFileName.substring(0, inputFileName.length()-3) + "." + imageExtension;
	        }
	        
	        if (!imageExtension.equals("png") && !imageExtension.equals("bmp")) {
	        	System.out.println("image file type unsupported");
	        	System.exit(-1);
	        }
	        
	        ParserHelper.fov = fov;
	        Scene scene = null;
	        
	        scene= Parser.instance().parse(inputFileName);
	        RayCaster rc = new RayCaster();
	        BufferedImage bi = rc.Render(scene, width, height);
	        
	        if (imageExtension.equals("png")) {
	        	rc.savePNG(bi, outputFileName);
	        } else {
	        	rc.saveBMP(bi, outputFileName);
	        }
	        
	        System.out.println("Raycasting done!");
	        if (line.hasOption("t")) {
	        	System.out.println("time elapsed: " + (System.currentTimeMillis() - time) + " ms.");
	        }
	        
		} catch (FactoryException e) {
			System.out.println("Parse error: " + e.getMessage());
			System.exit(-1);
		} catch (ParseException e) {
			formatter.printHelp("RayCast", options);
			System.out.println(e.getMessage());
			System.exit(-1);
			
		} catch (Exception e) {
			
			System.out.println("Raycasting error..." );
			System.exit(-1);
		}
		
	}
	
	@SuppressWarnings("static-access")
	public static void init() {
		options = new Options();
		i = OptionBuilder.withArgName("input file").hasArg()
			.withDescription("scene file name")
			.create("i");
		i.setRequired(true);
		
		o = OptionBuilder.withArgName("output file").hasArg()
			.withDescription("ouput file name")
			.create("o");
		
		fov = OptionBuilder.withArgName("horizontal angle").hasArg()
			.withDescription("horizontal angle")
			.create("fov");
		
		size = OptionBuilder.withArgName("size").hasArg()
			.withDescription("<ancho>x<alto>")
			.create( "size" );
		size.setRequired(true);
		
		time = new Option("t", false, "show elapsed time");
		
		options.addOption(i);
		options.addOption(o);
		options.addOption(fov);
		options.addOption(size);
		options.addOption(time);
		
	}

}

